package org.example.service.imp;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.example.dao.repository.ElasticRepository;
import org.example.domain.DiscussPost;
import org.example.domain.User;
import org.example.service.ElasticSearchService;
import org.example.util.CommonParam;
import org.example.util.HutoolUtil;
import org.example.vo.IndexPageVO;
import org.example.vo.LimitPageVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class ElasticSearchServerImp implements ElasticSearchService {
    private Logger logger = LoggerFactory.getLogger(ElasticSearchServerImp.class);
    @Autowired
    private UserServiceImp userServiceImp;
    @Autowired
    private ElasticRepository elasticRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HutoolUtil hutoolUtil;
    @Override
    public int saveOneDiscussPost(DiscussPost discussPost) {
        if (discussPost==null || discussPost.getId()<=0) return 0;
        try {
            elasticRepository.save(discussPost);
        }catch (Exception e){
            logger.error(e.toString());
            return 0;
        }
        return 1;
    }

    @Override
    public int saveListDiscussPost(List<DiscussPost> discussPostList) {
        if (discussPostList==null && discussPostList.size()<=0) return 0;
        try {
            elasticRepository.saveAll(discussPostList);
        }catch (Exception e){
            logger.error(e.toString());
            return 0;
        }
        return 1;
    }

    @Override
    public int deleteOneDiscussPost(int id) {
        if (id<=0) return 0;
        try {
            elasticRepository.deleteById(id);
        }catch (Exception e){
            logger.error(e.toString());
            return 0;
        }
        return 1;
    }
    @Autowired
    private DiscussServiceImp discussServiceImp;
    @Override
    public IndexPageVO search(String content, int page, int size) {
        if (hutoolUtil.stringIsEmpty(content)) return null;
        //先获取总数 额 感觉有点蠢
        NativeSearchQuery s = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(content,CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[0],CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[1])).build();
        Page<DiscussPost> search = elasticRepository.search(s);
        int totalCount = search.getContent().size();
        LimitPageVO limitPageVO = hutoolUtil.limitPage(page, size, totalCount);
        if (page>limitPageVO.getTotal()) return null;
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(content, CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[0],CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[1]))
                .withSort(SortBuilders.fieldSort(CommonParam.ES_SORT_DISCUSS_FIELD_NAMES[2]).order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort(CommonParam.ES_SORT_DISCUSS_FIELD_NAMES[0]).order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort(CommonParam.ES_SORT_DISCUSS_FIELD_NAMES[1]).order(SortOrder.DESC))

                .withPageable(PageRequest.of(limitPageVO.getCurrent()-1,10))//page就是页码
                .withHighlightFields(
                        new HighlightBuilder.Field(CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[0]).preTags("<em>").postTags("</em>"),
                        new HighlightBuilder.Field(CommonParam.ES_SEARCH_DISCUSS_BY_FIELD_NAMES[1]).preTags("<em>").postTags("</em>")
                )
                        .build();
        AggregatedPage<DiscussPost> result = elasticsearchTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                SearchHit[] hits = response.getHits().getHits();
                if (hits == null || hits.length <=0) return null;
                List<DiscussPost> result = new ArrayList<>();
                for (SearchHit temp : hits){
                    Map<String, Object> sourceAsMap = temp.getSourceAsMap();
                    DiscussPost discussPost = new DiscussPost();
                    discussPost.setId((Integer) sourceAsMap.get("id"));
                    discussPost.setUserId((Integer) sourceAsMap.get("userId"));
                    Map<String, HighlightField> highlightFields = temp.getHighlightFields();
                    if (highlightFields.containsKey("title")){
                        discussPost.setTitle(highlightFields.get("title").getFragments()[0].toString());
                    }else {
                        discussPost.setTitle((String) sourceAsMap.get("title"));
                    }
                    if (highlightFields.containsKey("content")){
                        discussPost.setContent(highlightFields.get("content").getFragments()[0].toString());
                    }else {
                        discussPost.setContent((String) sourceAsMap.get("content"));
                    }
                    discussPost.setType((Integer) sourceAsMap.get("type"));
                    discussPost.setStatus((Integer) sourceAsMap.get("status"));
                    discussPost.setCommentCount((Integer) sourceAsMap.get("commentCount"));
                    discussPost.setScore((Double) sourceAsMap.get("score"));
                    discussPost.setCreateTime(new Date((Long) sourceAsMap.get("createTime")));
                    result.add(discussPost);
                }
                return new AggregatedPageImpl(result,pageable,response.getHits().getTotalHits(),response.getAggregations(),response.getScrollId(),response.getHits().getMaxScore());
            }
        });
        IndexPageVO indexPageVO = new IndexPageVO();
        indexPageVO.setLimitPageVO(limitPageVO);
        List<DiscussPost> content1 = result.getContent();
        indexPageVO.setDiscussPost(content1);
        List<User> relationUser = new ArrayList<>();
        for (int i = 0;i<content1.size();i++){
            User user = userServiceImp.searchById(content1.get(i).getUserId());
            relationUser.add(user);
        }

        indexPageVO.setRelationUser(relationUser);
        return indexPageVO;
    }
}
